
#include "TwoStarWizard.h" 

#include <QWidget>
#include <QWizard>
#include <QLabel>
#include <QCheckBox>
#include <QVBoxLayout>
#include <cstdio>
#include <QVariant>

TwoStarWizard::TwoStarWizard(QWidget* parent)
: QWizard(parent)
 {
   //starpairs = new StarSelect();
   choosestarspage=new ChooseStarsPage();
   starsalignpage=new StarsAlignPage();
   addPage(new IntroPage());
   addPage(choosestarspage);
   addPage(starsalignpage);
     //addPage(new OutputFilesPage);
     //addPage(new ConclusionPage);

     //setPixmap(QWizard::BannerPixmap, QPixmap(":/images/banner.png"));
     //setPixmap(QWizard::BackgroundPixmap, QPixmap(":/images/background.png"));

     //setWindowTitle("Class Wizard");
   setGeometry(0, 0, 640, 425);
   setParent(parent);
 }

void TwoStarWizard::accept()
{

    QDialog::accept();
}


void TwoStarWizard::setTelescope(INDI::BaseDevice *basedev )
{

  INDI::Telescope *t = static_cast<INDI::Telescope *>(basedev);
  setField("mountConnected", QVariant(true));
  //if (t.canSync()) {
  //  setField("scopeCanSync", QVariant(true));
  //}
  telescope = t;
  starsalignpage->setTelescope(telescope);
 
}

void TwoStarWizard::setClient(INDI::BaseClient* c)
{
  client = c;
  starsalignpage->setClient(client);
}

INDI::BaseClient* TwoStarWizard::getClient()
{
  return client;
}


void TwoStarWizard::setStarPairs(StarSelect* sp)
{
  starpairs = sp;
  choosestarspage->setStarPairs(sp);
  starsalignpage->setStarPairs(sp);
}


void TwoStarWizard::setParent(QWidget *parent)
{
    printf("SetParent\n");
  this->setParent(parent, 0);
}

void TwoStarWizard::setParent(QWidget* parent, Qt::WindowFlags f)
{
    printf("SetParent flags %d\n", (int)f);
  QWidget::setParent(parent, 0);
}

IntroPage::IntroPage(QWidget *parent)
: QWizardPage(parent)
{
     setTitle(tr("Introduction"));
     //setPixmap(QWizard::WatermarkPixmap, QPixmap(":/images/watermark1.png"));

     label = new QLabel("This wizard calculates the misalignment of your equatorial mount. "
                        "It takes a sighting on two stars (using slew/sync), and determines "
			"the polar alignment of your scope. You could afterwards better align "
		        "your scope by manually realigning the second star using the alt/az "
			"knobs of the mount.");
     label->setWordWrap(true);
     mountConnectedCheckBox = new QCheckBox("Mount connected");
     mountConnectedCheckBox->setChecked(false);
     mountConnectedCheckBox->setDisabled(true);
     registerField("mountConnected*", mountConnectedCheckBox);
     //scopeCanSync = new QCheckBox("Mount can Sync");
     //scopeCanSync->setChecked(false);
     //scopeCanSync->setDisabled(true);
     //registerField("scopeCanSync", scopeCanSync);    
     
     
     QVBoxLayout *layout = new QVBoxLayout;
     layout->addWidget(label);
     layout->addWidget(mountConnectedCheckBox);
     //layout->addWidget(scopeCanSync);     
     setLayout(layout);
 }
 
 ChooseStarsPage::ChooseStarsPage(QWidget *parent)
 :QWizardPage(parent)
 {
  setTitle(tr("Choose a pair of stars"));
  choosestarslabel=new QLabel("Here are listed possible pairs of stars you can use. "
			      "All listed stars are currently visible from your site, "
			      "and pairs have been chosen so as to improve accuracy."
		       );
  choosestarslabel->setWordWrap(true);
  
  starpairstableView = new QTableView();
  starpairstableView->setStyleSheet("font-size: 8pt;");
  starpairstableView->setSelectionBehavior(QAbstractItemView::SelectRows);
  starpairstableView->setSelectionMode(QAbstractItemView::SingleSelection);
  starpairstableView->setSortingEnabled(false);
  
  //registerField("rowselected*", this, "rowselected", SIGNAL(rowchanged(QModelIndex)));
  qRegisterMetaType<QItemSelectionModel *>("QItemSelectionModel*");
  //starpairstreeView->setModel(model);
  QVBoxLayout *layout = new QVBoxLayout;
  layout->addWidget(choosestarslabel);
  layout->addWidget(starpairstableView);
     //layout->addWidget(scopeCanSync);     
  setLayout(layout); 
  
 }

void ChooseStarsPage::setStarPairs(StarSelect* sp)
{
  starpairs = sp;
}

void ChooseStarsPage::initializePage()
{
  starpairs->actualizeAltAz();
  starpairs->computePairs();
  starpairstableView->setModel(starpairs);
  starpairstableView->resizeColumnsToContents();
  starpairstableView->resizeRowsToContents();
  
  starpairstableView->setSelectionModel(new QItemSelectionModel(starpairs));
  starpairstableView->selectRow(0);
  registerField("starPairSelection", this, "selectionModel");
  //connect(starpairstableView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &,const QItemSelection &)), 
	//  this, SLOT(changeStars(const QItemSelection &,const QItemSelection &)));
}
/*
void ChooseStarsPage::changeStars(const QItemSelection &selected, const QItemSelection &deselected)
{
  QModelIndexList rows=starpairstableView->selectionModel()->selectedRows();
  QModelIndex row=rows.at(0);
  IDLog("Selected pair %d\n", row.row());
  rowselected = rows.at(0);
  validatePage();
  emit rowchanged(rowselected);
}
*/
StarsAlignPage::StarsAlignPage(QWidget* parent): QWizardPage(parent)
{
  
  initialsyncra=0.0; initialsyncde=0.0;

  setTitle(tr("Slew 'n Sync"));
  starsalignlabel = new QLabel("Proceed with alignment of the two selected stars. "
			      "Use the button to begin slewing to the first star. "
			      "You can sync stars either with the button or with the pad."
		       );
  starsalignlabel->setWordWrap(true);
  
  star1gb=new QGroupBox(parent);
  star1gb->setTitle("Star 1");
  
  QGridLayout *gridl=new QGridLayout();
  QLabel *l = new QLabel("Name:"); gridl->addWidget(l, 0, 0);
  l = new QLabel("RA:"); gridl->addWidget(l, 1, 0);
  l = new QLabel("DEC:"); gridl->addWidget(l, 2, 0);
  l = new QLabel("dRA:"); gridl->addWidget(l, 3, 0);
  l = new QLabel("dDEC:"); gridl->addWidget(l, 4, 0);
  
  star1name = new QLabel("--"); star1RA=new QLabel("--"); star1DEC=new QLabel("--"); 
  star1dRA=new QLabel("--"); star1dDEC=new QLabel("--");  

  gridl->addWidget(star1name, 0, 1); gridl->addWidget(star1RA, 1, 1); gridl->addWidget(star1DEC, 2, 1); 
  gridl->addWidget(star1dRA, 3, 1); gridl->addWidget(star1dDEC, 4, 1);
  star1gb->setLayout(gridl);
  
  star2gb=new QGroupBox(parent);
  star2gb->setTitle("Star 2");
  
  gridl=new QGridLayout(); 
  l = new QLabel("Name:"); gridl->addWidget(l, 0, 0);
  l = new QLabel("RA:"); gridl->addWidget(l, 1, 0);
  l = new QLabel("DEC:"); gridl->addWidget(l, 2, 0);
  l = new QLabel("dRA:"); gridl->addWidget(l, 3, 0);
  l = new QLabel("dDEC:"); gridl->addWidget(l, 4, 0);
  
  star2name = new QLabel("--"); star2RA=new QLabel("--"); star2DEC=new QLabel("--"); 
  star2dRA=new QLabel("--"); star2dDEC=new QLabel("--"); 
  
  gridl->addWidget(star2name, 0, 1); gridl->addWidget(star2RA, 1, 1); gridl->addWidget(star2DEC, 2, 1); 
  gridl->addWidget(star2dRA, 3, 1); gridl->addWidget(star2dDEC, 4, 1);
  star2gb->setLayout(gridl);
  
  starslayout = new QHBoxLayout();
  starslayout->addWidget(star1gb);
  starslayout->addWidget(star2gb);
  
  machinegb = new QGroupBox();
  machinegb->setTitle("Proceed");
  
  statebutton = new QPushButton("Init");
  initializeStateMachine(statebutton);
  machinelayout = new QHBoxLayout();
  machinelayout->addWidget(statebutton);
  machinegb->setLayout(machinelayout);
  
  layout = new QVBoxLayout;
  layout->addWidget(starsalignlabel);
  layout->addLayout(starslayout);
  layout->addWidget(machinegb);
 
  setLayout(layout); 
  
  connect(&starsalignstatemachine, SIGNAL(finished()), this, SLOT(sethasFinished()));
  connect(&waitforSlewStar1, SIGNAL(entered()), this, SLOT(waitslewstar1()));
  connect(&slewStar1, SIGNAL(entered()), this, SLOT(starslewed()));
  connect(&syncStar1, SIGNAL(entered()), this, SLOT(syncstar1()));
  connect(&waitforSlewStar2, SIGNAL(entered()), this, SLOT(waitslewstar2()));
  connect(&slewStar2, SIGNAL(entered()), this, SLOT(starslewed()));
  connect(&syncStar2, SIGNAL(entered()), this, SLOT(syncstar2()));
  
}

void StarsAlignPage::setStarPairs(StarSelect* sp)
{
  starpairs = sp;
}

void StarsAlignPage::setTelescope(INDI::Telescope* t)
{
  telescope = t;
}

void StarsAlignPage::setClient(INDI::BaseClient* c)
{
  client = c;
}


void StarsAlignPage::initializePage()
{
  char sexa[13];
  QWizardPage::initializePage();
  QItemSelectionModel *selectpair=field("starPairSelection").value<QItemSelectionModel *>();
  spair = starpairs->getPair(selectpair->selectedRows().at(0));
  star1 = spair.first;
  star2 = spair.second;
  IDLog("Star 1 %s Star2 %s \n", star1->starentry->name.toAscii().data(), star2->starentry->name.toAscii().data());
  star1name->setText(star1->starentry->name);
  fs_sexa(sexa, star1->ranow,2, 3600);
  star1RA->setText(QString(sexa));
  fs_sexa(sexa, star1->denow,3, 3600);
  star1DEC->setText(QString(sexa));
  
  star2name->setText(star2->starentry->name);
  fs_sexa(sexa, star2->ranow,2, 3600);
  star2RA->setText(QString(sexa));
  fs_sexa(sexa, star2->denow,3, 3600);
  star2DEC->setText(QString(sexa)); 
  
  if (starsalignstatemachine.isRunning()) starsalignstatemachine.stop();
  hasfinished = false;
  emit completeChanged();
  starsalignstatemachine.start();
  
  
}

void StarsAlignPage::initializeStateMachine(QPushButton *button)
{
 
 init.assignProperty(button, "text", "Slew star 1");
 init.addTransition(button, SIGNAL(clicked()), &waitforSlewStar1);
 
 waitforSlewStar1.assignProperty(button, "text", "Waiting slew to Star 1");
 waitforSlewStar1.addTransition(this, SIGNAL(mountslewed()), &slewStar1);
 
 slewStar1.assignProperty(button, "text", "Sync Star 1");
 slewStar1.addTransition(button, SIGNAL(clicked()), &waitsyncStar1);
 slewStar1.addTransition(this, SIGNAL(mountsynced()), &syncStar1);
 
 syncStar1.assignProperty(button, "text", "Slew Star 2");
 syncStar1.addTransition(button, SIGNAL(clicked()), &waitforSlewStar2);
 
 waitforSlewStar2.assignProperty(button, "text", "Waiting slew to Star 2");
 waitforSlewStar2.addTransition(this, SIGNAL(mountslewed()), &slewStar2);
 
 waitsyncStar1.assignProperty(button, "text", "Waiting Sync...");
 waitsyncStar1.addTransition(this, SIGNAL(mountsynced()), &syncStar1);
 
 slewStar2.assignProperty(button, "text", "Sync Star 2");
 slewStar2.addTransition(button, SIGNAL(clicked()), &waitsyncStar2);
 slewStar2.addTransition(this, SIGNAL(mountsynced()), &syncStar2);
 
 //syncStar2.assignProperty(button, "text", "Restart");
 
 waitsyncStar2.assignProperty(button, "text", "Waiting Sync...");
 waitsyncStar2.addTransition(this, SIGNAL(mountsynced()), &syncStar2);
 
 //finish.addTransition(&init);

 starsalignstatemachine.addState(&init);
 starsalignstatemachine.addState(&waitforSlewStar1);
 starsalignstatemachine.addState(&slewStar1);
 starsalignstatemachine.addState(&syncStar1);
 starsalignstatemachine.addState(&waitsyncStar1);
 starsalignstatemachine.addState(&waitforSlewStar2);
 starsalignstatemachine.addState(&slewStar2);
 starsalignstatemachine.addState(&syncStar2);
 starsalignstatemachine.addState(&waitsyncStar2);
 //starsalignstatemachine.addState(&finish);
 starsalignstatemachine.setInitialState(&init);
  
}

void StarsAlignPage::sethasFinished()
{
  hasfinished = true;
  emit completeChanged();
}


bool StarsAlignPage::isComplete() const
{
  return hasfinished;
}

void StarsAlignPage::cleanupPage()
{
  starsalignstatemachine.stop();
  QWizardPage::cleanupPage();
}

void StarsAlignPage::restart()
{
  star1dRA->setText(QString("--"));
  star1dDEC->setText(QString("--")); 
  star2dRA->setText(QString("--"));
  star2dDEC->setText(QString("--"));   
  starsalignstatemachine.stop();
  hasfinished = false;
  emit completeChanged();
  initializeStateMachine(statebutton);
  starsalignstatemachine.start();
}


void StarsAlignPage::slewtostar(struct StarSelect::star *star)
{
  INumberVectorProperty *eqcoords = telescope->getNumber("EQUATORIAL_EOD_COORD");
  ISwitchVectorProperty *slewmode= telescope->getSwitch("ON_COORD_SET");
  ISwitch *track = IUFindSwitch(slewmode, "TRACK");
  
  IUResetSwitch(slewmode);
  track->s=ISS_ON;
  client->sendNewSwitch(slewmode);
  
  INumber *racoord=IUFindNumber(eqcoords, "RA");
  racoord->value=star->ranow;
  INumber *decoord=IUFindNumber(eqcoords, "DEC");
  decoord->value=star->denow;
  
  client->sendNewNumber(eqcoords);

  
}

void StarsAlignPage::waitslewstar1()
{
  slewtostar(star1);
  connect(hApp->getHandController(), SIGNAL(newgoto(double,double)), this, SLOT(waitgoto(double,double))); 
}

void StarsAlignPage::waitslewstar2()
{
  slewtostar(star2);
  connect(hApp->getHandController(), SIGNAL(newgoto(double,double)), this, SLOT(waitgoto(double,double))); 
}


void StarsAlignPage::starslewed()
{
  disconnect(hApp->getHandController(), SIGNAL(newgoto(double,double)), this, SLOT(waitgoto(double,double))); 
  connect(statebutton, SIGNAL(clicked(bool)), this, SLOT(syncpad()));
  connect(hApp->getPad(), SIGNAL(lastgotosynced(double,double)), this, SLOT(keepsyncstar(double,double))); 
}


void StarsAlignPage::syncstar(StarSelect::star* st)
{
  char sexa[13];
  if (st == star1) {
    star1syncra = syncedra - initialsyncra;
    star1syncde = syncedde - initialsyncde;
    fs_sexa(sexa, star1->ranow - star1syncra, 2, 360000);
    star1dRA->setText(sexa);
    fs_sexa(sexa, star1->denow - star1syncde, 3, 360000);
    star1dDEC->setText(sexa);
  }
  else {
    star2syncra = syncedra - (star1->ranow - star1syncra);
    star2syncde = syncedde - (star1->denow - star1syncde);
    fs_sexa(sexa, star2->ranow - star2syncra, 2, 360000);
    star2dRA->setText(sexa);
    fs_sexa(sexa, star2->denow - star2syncde, 3, 360000);
    star2dDEC->setText(sexa);    
    initialsyncra = star2->ranow - star2syncra;
    initialsyncde = star2->denow - star2syncde;
    statebutton->setText("Restart");
    connect(statebutton, SIGNAL(clicked(bool)), this, SLOT(restart()));
  }    
  //statebutton->click();
}

void StarsAlignPage::syncstar1()
{
  syncstar(star1);
}

void StarsAlignPage::syncstar2()
{
  syncstar(star2);
}

void StarsAlignPage::syncpad()
{
  QMouseEvent event(QEvent::MouseButtonPress, QPoint(0,0), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);  
  QApplication::sendEvent(hApp->getPad()->getPadButtonEvents().value("SYNC")->getButton(), &event);  
  disconnect(statebutton, SIGNAL(clicked(bool)), this, SLOT(syncpad()));
  QMouseEvent event2(QEvent::MouseButtonRelease, QPoint(0,0), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);  
  QApplication::sendEvent(hApp->getPad()->getPadButtonEvents().value("SYNC")->getButton(), &event2);    
}

void StarsAlignPage::keepsyncstar(double ra, double dec)
{
  syncedra = ra;
  syncedde = dec;
  IDLog("keepsyncstar %g %g\n", ra, dec);
  disconnect(hApp->getPad(), SIGNAL(lastgotosynced(double,double)), this, SLOT(keepsyncstar(double,double)));
  emit mountsynced();
}

void StarsAlignPage::waitgoto(double ra, double dec)
{
  disconnect(hApp->getHandController(), SIGNAL(newgoto(double,double)), this, SLOT(waitgoto(double,double)));  
  emit mountslewed();
}
